import re
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Lasso
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.neighbors import KNeighborsRegressor

df=pd.read_excel(R"D:\PYCHARM文件\zwz050418\main\house.xlsx")

d1 = df

# 将非数字的字符串替换为 NaN
d1['建筑年代'] = pd.to_numeric(d1['建筑年代'], errors='coerce')

# 处理 NaN 值，这里我们选择删除含有 NaN 的行
d1.dropna(subset=['建筑年代'], inplace=True)

# 再次检查数据类型和值（可选）
print(d1['建筑年代'].dtype)  # 这应该还是 float，因为 NaN 被替换进来了
print(d1['建筑年代'].unique())

# 如果确定所有值都是整数，并且没有 NaN，则可以安全地转换为 int32
d1['建筑年代'] = d1['建筑年代'].astype('Int32')

print(d1)

# 分解户型
def apart_room(x):
    if pd.isnull(x) or x == '暂无':
        return 0
    return int(x.split('室')[0])


def apart_hall(x):
    # 使用正则表达式查找 '厅' 后面的数字
    match = re.search(r'厅(\d+)', x)
    if match:
        # 如果找到了，返回匹配的数字
        return int(match.group(1))
    else:
        # 如果没有找到，返回 0
        return 0

def apart_wc(x):
    if pd.isnull(x) or '卫' not in x:
        return 0
    try:
        return int(re.search(r'(\d+)卫', x).group(1))
    except AttributeError:
        return 0

# 应用分解
d1['室'] = d1['户型'].map(apart_room)
d1['厅'] = d1['户型'].map(apart_hall)
d1['卫'] = d1['户型'].map(apart_wc)
# 删除楼层、户型、单价
d1.drop(columns=['户型','楼层','单价'],inplace=True)

print(d1.columns)

#唯一标签值
print(df['朝向'].unique())
print("-"*50)
print(df['地区'].unique())
print("-"*50)
print(df['装修程度'].unique())
print("-"*50)
print(df['产权性质'].unique())
print("-"*50)
print(df['住宅类别'].unique())
print("-"*50)
print(df['建筑结构'].unique())
print("-"*50)
print(df['建筑形式'].unique())
print("-"*50)
print(df['建筑年代'].unique())
print("-"*50)
print(df['有无电梯'].unique())
print("-"*50)

# 编码-有序多分类（根据上面可视化的结果，按照对价格的影响程度排序，越大影响越高）
# 无序多分类无法直接引入，必须“哑元”化变量
# 等级变量（有序多分类）可以直接引入模型
# ['东' '南北' '北' '西' '南' '东南' '西北' '东西' '东北' '西南北' '西南' '东西南北']
map1 = {'南':4, '南北':3, '北':5, '西南':7, '东西':6, '东':6, '东北':9, '东南':6, '西':5, '西北':8, '西南北':6, '东西南北':1}
d1['朝向'] = d1['朝向'].map(map1)

# ['精装修' '毛坯' '豪华装修' '简装修' '中装修' nan]
map2 = {'毛坯':1, '简装修':2, '精装修':3, '中装修':4, '豪华装修':5}
d1['装修程度'] = d1['装修程度'].map(map2)

# ['无 ' '有 ']
map3 = {'有 ':1, '无 ':0}
d1['有无电梯'] = d1['有无电梯'].map(map3)

# [' 商品房 ' '个人产权' nan '限价房' '经济适用房' '单位产权' ' 成本价房改房 ' '使用权' ' 个人产权 ']
map4 = {' 商品房 ':5, '个人产权':7,' 个人产权 ':7, '商品房(免税)':7, '使用权':2, '经济适用房':6, ' 成本价房改房 ':3, '限价房':8, '单位产权':7}
d1['产权性质'] = d1['产权性质'].map(map4)

# ['普通住宅' '公寓' nan '商业办公类' '四合院' ' 普通住宅 ']
map5 = {'普通住宅':5," 普通住宅 ":5, '商业办公类':4, '公寓':3, '四合院':2}
d1['住宅类别'] = d1['住宅类别'].map(map5)

# ['平层' nan '复式' '开间' ' 平层 ' '跃层' '错层']
map6 = {'平层':4,' 平层 ':4, '开间':2, '跃层':5, '错层':1, '复式':3}
d1['建筑结构'] = d1['建筑结构'].map(map6)

# map7 = {'叠加':1, '独栋':2, '联排':3}
# d1['建筑形式'] = d1['建筑形式'].map(map7)

# ' 朝阳 ' ' 东城 ' ' 西城 ' ' 顺义 ' ' 昌平 ' ' 密云 ' ' 房山 ' ' 通州 ' ' 燕郊 ' ' 海淀 '
#  # ' 门头沟 ' ' 丰台 ' ' 大兴 ' ' 怀柔 ' ' 石景山 ' ' 北京周边 '
map8 = {' 朝阳 ':16, ' 东城 ':15, ' 西城 ':14, ' 顺义 ':13, ' 昌平 ':12, ' 密云 ':11, ' 房山 ':10, ' 通州 ':9,' 燕郊 ':8, ' 海淀 ':7,
     ' 门头沟 ':6, ' 丰台 ':5, ' 大兴 ':4, ' 怀柔 ':3,' 石景山 ':2,' 北京周边 ':1}
d1['地区'] = d1['地区'].map(map8)
# 删除超过2019年的房子，年代转变为房龄
d1['建筑年代'] = d1['建筑年代'].astype('int32')
d1.drop(index=d1[d1['建筑年代']>2019].index,inplace=True)
d1['房龄'] = d1['建筑年代'].map(lambda x: 2020-x)
d1.drop(columns=['建筑年代'],inplace=True)
d1.drop(columns=['网址'],inplace=True)
d1.drop(columns=['挂牌时间'],inplace=True)
d1.drop(columns=['建筑形式'],inplace=True)
d1.drop(columns=['车库数量'],inplace=True)
d1.drop(columns=['车位数量'],inplace=True)
d1 = d1.dropna()
# 建立评分后的表格
d1.to_csv(R"D:\PYCHARM文件\zwz050418\main\d1-tets1.csv",encoding="utf-8-sig",index=False)
print(d1.head())

y = d1['总价']
X = d1.drop(columns=['总价'])

print(X.head())
print(y.head())

X = d1.drop(['总价'], axis=1)
y = d1['总价']

# 确保所有特征都是数值类型，并处理 NaN、无穷大或过大的数值
for col in X.columns:
    # 检查列中是否有 NaN 值
    if X[col].isnull().any():
        # 用列的中位数替换 NaN 值
        median_value = X[col].median()
        X[col] = X[col].fillna(median_value)

    # 检查并替换无穷大值
    X[col] = X[col].replace([np.inf, -np.inf], np.nan)
    X[col] = X[col].fillna(0)  # 用0或其他适当的值替换无穷大值

    # 如果有列包含非数值型数据，需要转换为数值型
    # 这里以 '面积' 为例，假设它包含 '平米' 单位
    if X[col].dtype == object:
        X[col] = X[col].str.replace('平米', '').astype(float)

# 再次检查确保没有 NaN 值
if X.isnull().values.any():
    X = X.dropna(axis='columns')

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=33)

# 使用 PolynomialFeatures 之前确保所有特征都是数值类型
X_train_numeric = X_train.select_dtypes(include=[np.number])
X_test_numeric = X_test.select_dtypes(include=[np.number])

# 创建 PolynomialFeatures 实例
poly = PolynomialFeatures(degree=2)

# 应用多项式特征转换
x_train = poly.fit_transform(X_train_numeric)
x_test = poly.transform(X_test_numeric)


# 套索回归

la = Lasso(alpha=0.1,max_iter=100000)
la.fit(x_train,y_train)
print(f'套索回归训练集得分：{round(la.score(x_train,y_train),2)}')
print(f'测试集得分：{round(la.score(x_test,y_test),2)}')

# 随机森林

rf = RandomForestRegressor()
rf.fit(x_train,y_train)
print(f'随机森林训练集得分：{round(rf.score(x_train,y_train),2)}')
print(f'测试集得分：{round(rf.score(x_test,y_test),2)}')

# 决策树

dt = DecisionTreeRegressor(max_depth = 6)
dt.fit(x_train,y_train)
print(f'决策树训练集得分：{round(dt.score(x_train,y_train),2)}')
print(f'测试集得分：{round(dt.score(x_test,y_test),2)}')
# k近邻

kn = KNeighborsRegressor(n_neighbors=20)
kn.fit(x_train,y_train)
print(f'k近邻训练集得分：{round(kn.score(x_train,y_train),2)}')
print(f'测试集得分：{round(kn.score(x_test,y_test),2)}')

apply = np.array([95,10,4,0,5,4,4,5,6,1,3,1,1,10]).reshape(1,-1)
poly_apply = poly.fit_transform(apply)
print('------------总价预测结果-------------')
print(f'线性回归：{round(la.predict(poly_apply)[0],2)}万元')
print(f'随机森林回归：{round(rf.predict(poly_apply)[0],2)}万元')
print(f'决策树回归：{round(dt.predict(poly_apply)[0],2)}万元')
print(f'K近邻回归：{round(kn.predict(poly_apply)[0],2)}万元')
print('------------综合预测结果-------------')
print(round(((la.predict(poly_apply)+rf.predict(poly_apply)+dt.predict(poly_apply)+kn.predict(poly_apply))/4.0)[0],2),'万元')